home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / program / flower.zip / main.c < prev    next >
Text File  |  1997-06-24  |  36KB  |  1,237 lines

  1.  
  2. /* Copyright (c) 1996, 1997 Craig Schneiderwent */
  3. /*
  4. Program: flower
  5. File:    main.c
  6. Author:  Craig Schneiderwent
  7.          74631.165@compuserve.com
  8. Date:    06-Apr-1996
  9.  
  10. Mainline processing, algorithm to find
  11. function declarations and calls.
  12.  
  13. */
  14.  
  15.  
  16. /* My apologies to the non-ASCII folks */
  17. #define CARRIAGE_RETURN 13
  18. #define LINE_FEED       10
  19.  
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <ctype.h>
  23. #include <string.h>
  24. #include <limits.h>
  25. #include "mydebug.h"
  26. #include "structs.h"
  27. #include "mniplist.h"
  28. #include "updtlist.h"
  29. #include "memfunc.h"
  30. #include "printrpt.h"
  31.  
  32. struct exFunc {
  33.     char funcNm[ MAXFUNCNAMESIZE ];
  34.     struct exFunc *next;
  35.     struct exFunc *prev;
  36. } ;
  37.  
  38. struct flowerOptions {
  39.     short  rqstTreeRpt;
  40.     short  rqstCalledRpt;
  41.     short  rqstCalledByRpt;
  42.     int    file;
  43.     int    fromFile;
  44.     int    nbFiles;
  45.     int    exFuncStrt;
  46.     char   listOfFilesFileNm[ MAXFILENAMESIZE ];
  47.     struct exFunc *excludedFuncs;
  48. } ;
  49.  
  50. int sussOptions( struct flowerOptions *
  51.                , int
  52.                , char *[] );
  53. int setExFuncListFromFile( struct flowerOptions *
  54.                          , char * );
  55. int addToExFuncList( struct flowerOptions *
  56.                    , char * );
  57. void freeExFuncList( struct flowerOptions * );
  58. int processFiles( FILE *
  59.                 , struct fileInfo *
  60.                 , struct flowerOptions * );
  61. void cleanUpFileName( char * );
  62. void processTheText( char *
  63.                    , char **
  64.                    , char * 
  65.                    , int  *
  66.                    , struct fileInfo *
  67.                    , struct flowerOptions * );
  68. char *getNextToken( char *, char *, char * );
  69. char *getPrevToken( char *, char * );
  70. int getCalledFunction( char *
  71.                      , char *
  72.                      , char *
  73.                      , struct flowerOptions * );
  74. int getCurrentFunction( char *
  75.                       , char *
  76.                       , char *
  77.                       , struct flowerOptions * );
  78. int fooledByStructOrUnion( char *, char * );
  79. int isReservedWord( char * );
  80. int isReservedSymbol( char * );
  81. int isExcludeFunc( char *, struct flowerOptions * );
  82. int isExcludedFunc( char *
  83.                   , struct flowerOptions * );
  84. void cleanUpFuncName( char * );
  85. int isEmbeddedSymbol( char );
  86.  
  87. int main( int argc, char *argv[] )
  88. {
  89.     #ifdef MY_DEBUG
  90.     char                      *thisFuncNm = "main\0";
  91.     char                      debug_msg[ MY_DEBUG_MSG_SZ ];
  92.     int                       debug_arg_index = 0;
  93.     #endif
  94.     int                       rc = 0;
  95.     int                       limit = 0;
  96.     int                       file = 0;
  97.     FILE                      *input;
  98.     FILE                      *listOfFiles;
  99.     char                      aFileNm[ MAXFILENAMESIZE ];
  100.     char                      holder[ MAXFILENAMESIZE ];
  101.     struct fileInfo           fileList;
  102.     struct fileInfo           *currentFile = NULL;
  103.     struct isCalledByFuncInfo calledByList;
  104.     struct flowerOptions      options = { 1, 1, 1, 1, 0, 0, 0, {"\0"}, NULL };
  105.  
  106.     #ifdef MY_DEBUG
  107.     TRACE_ENTRY( thisFuncNm );
  108.     for ( debug_arg_index=0; debug_arg_index < argc; debug_arg_index++ ) {
  109.         sprintf( debug_msg, "argv[ %d ] = %s"
  110.                , debug_arg_index, argv[ debug_arg_index ] );
  111.         TRACE_MSG( thisFuncNm, debug_msg );
  112.     } /* endfor */
  113.     #endif
  114.  
  115.     if ( argc < 2 ) {
  116.         showSyntax();
  117.         return( 0 );
  118.     } /* endif */
  119.  
  120.     initFileInfo( &fileList );
  121.     initIsCalledByFuncInfo( &calledByList );
  122.  
  123.     rc = sussOptions( &options, argc, argv );
  124.     if ( rc != 0 ) {
  125.         fprintf( stderr
  126.                , "\n***** error %d occurred during initialization *****\n"
  127.                , rc );
  128.         return( rc );
  129.     } /* endif */
  130.  
  131.     strcpy( holder, argv[ options.file ] );
  132.  
  133.     if ( options.fromFile ) {
  134.         listOfFiles = fopen( options.listOfFilesFileNm, "r" );
  135.         if ( listOfFiles == NULL ) {
  136.             fprintf( stderr, "%s unable to fopen() %s\n"
  137.                    , MYNAME, options.listOfFilesFileNm );
  138.             return( 1 );
  139.         } else {
  140.             while ( !feof( listOfFiles ) ) {
  141.                 fgets( aFileNm, MAXFILENAMESIZE, listOfFiles );
  142.                 if ( feof( listOfFiles ) ) {
  143.                     break;
  144.                 } /* endif */
  145.                 options.nbFiles++;
  146.             } /* endwhile */
  147.             rewind( listOfFiles );
  148.         } /* endif */
  149.     } /* endif */
  150.  
  151.     limit = options.file + options.nbFiles;
  152.     for ( file = options.file; file < limit; file++ ) {
  153.         if ( options.fromFile ) {
  154.             fgets( aFileNm, MAXFILENAMESIZE, listOfFiles );
  155.             cleanUpFileName( aFileNm );
  156.         } else {
  157.             strncpy( aFileNm, argv[ file ], MAXFILENAMESIZE );
  158.         } /* endif */
  159.         input = fopen( aFileNm, "rb" );
  160.         if ( input == NULL ) {
  161.             fprintf( stderr
  162.                    , "\n***** error on fopen() for %s *****\n"
  163.                    , aFileNm );
  164.             return( 1 );
  165.         } /* endif */
  166.         rc = addToFileList( &fileList, aFileNm );
  167.         if ( rc != 0 ) {
  168.             rc = 3;
  169.             fprintf( stderr
  170.                    , "\n***** error %ld occurred processing %s *****\n"
  171.                    , rc, aFileNm );
  172.             break;
  173.         } /* endif */
  174.         currentFile = endOfFileList( &fileList );
  175.         fprintf( stderr, "processing %s\n", aFileNm );
  176.         #ifdef MY_DEBUG
  177.         sprintf( debug_msg, "\tprocessing %s", aFileNm );
  178.         TRACE_MSG( thisFuncNm, debug_msg );
  179.         #endif
  180.         rc = processFiles( input, currentFile, &options );
  181.         if ( rc != 0 ) {
  182.             fprintf( stderr
  183.                    , "\n***** error %ld occurred processing %s *****\n"
  184.                    , rc
  185.                    , aFileNm );
  186.             break;
  187.         } /* endif */
  188.         if ( fclose( input ) ) {
  189.             fprintf( stderr
  190.                    , "\n***** error on fclose() for %s *****\n"
  191.                    , aFileNm );
  192.         } /* endif */
  193.     } /* endfor */
  194.  
  195.     if ( options.fromFile ) {
  196.         if ( fclose( listOfFiles ) ) {
  197.             fprintf( stderr
  198.                    , "\n***** error on fclose() for %s *****\n"
  199.                    , options.listOfFilesFileNm );
  200.             rc = 1;
  201.         } /* endif */
  202.     } /* endif */
  203.  
  204.     if ( rc == 0 ) {
  205.         fprintf( stderr, "updating called function file names\n" );
  206.         updateAllCalledFuncFileNm( &fileList );
  207.         fprintf( stderr, "updating called function base pointers\n" );
  208.         updateCalledFuncBase( &fileList );
  209.         fprintf( stderr, "checking for circular references\n" );
  210.         updateCircularReferences( &fileList );
  211.         if ( options.rqstCalledRpt ) {
  212.             fprintf( stderr, "printing called function report\n" );
  213.             printCalledFuncReport( &fileList );
  214.         } /* endif */
  215.         rc = 0;
  216.         if ( options.rqstCalledByRpt || options.rqstTreeRpt ) {
  217.             fprintf( stderr, "creating called-by function list\n" );
  218.             rc = createCalledByFuncList( &fileList, &calledByList );
  219.         } /* endif */
  220.         if ( rc == 0 ) {
  221.             if ( options.rqstCalledByRpt ) {
  222.                 fprintf( stderr, "printing calling function report\n" );
  223.                 printCallingFuncReport( &calledByList );
  224.             } /* endif */
  225.             fprintf( stderr, "updating not called functions\n" );
  226.             updateNotCalledFuncList( &fileList, &calledByList );
  227.             if ( options.rqstTreeRpt ) {
  228.                 fprintf( stderr, "printing call tree report\n" );
  229.                 printCallTreeReport( &fileList );
  230.             } /* endif */
  231.             freeExFuncList( &options );
  232.             freeLists( &fileList );
  233.             freeIsCalledByList( &calledByList );
  234.         } else {
  235.             fprintf( stderr
  236.                    , "\n***** error %ld occurred *****\n"
  237.                    , rc );
  238.         } /* endif */
  239.     } /* endif */
  240.  
  241.     #ifdef __DEBUG_ALLOC__
  242.     _dump_allocated( MAXFUNCNAMESIZE + MAXFILENAMESIZE );
  243.     #endif
  244.  
  245.     #ifdef MY_DEBUG
  246.     TRACE_EXIT( thisFuncNm );
  247.     #endif
  248.  
  249.     return( rc );
  250. }
  251.  
  252. int sussOptions( struct flowerOptions *pOptions
  253.                , int nbParms
  254.                , char *cmdLineOptions[] )
  255. {
  256.     int index = 0;
  257.     int rc = 0;
  258.  
  259.     if ( cmdLineOptions[ 1 ] [ 0 ] == '-' ) {
  260.         pOptions->rqstTreeRpt = 0;
  261.         pOptions->rqstCalledRpt = 0;
  262.         pOptions->rqstCalledByRpt = 0;
  263.         pOptions->file = 2;
  264.         while ( cmdLineOptions[ 1 ] [ index ] != '\0' ) {
  265.             switch ( cmdLineOptions[ 1 ] [ index ] ) {
  266.             case 'a':
  267.                 pOptions->rqstTreeRpt = 1;
  268.                 pOptions->rqstCalledRpt = 1;
  269.                 pOptions->rqstCalledByRpt = 1;
  270.                 break;
  271.             case 't':
  272.                 pOptions->rqstTreeRpt = 1;
  273.                 break;
  274.             case 'c':
  275.                 pOptions->rqstCalledRpt = 1;
  276.                 break;
  277.             case 'b':
  278.                 pOptions->rqstCalledByRpt = 1;
  279.                 break;
  280.             default:
  281.                 break;
  282.             } /* endswitch */
  283.             index++;
  284.         } /* endwhile */
  285.     } /* endif */
  286.  
  287.     pOptions->nbFiles = 0;
  288.  
  289.     for ( index = 1; index < nbParms; index++ ) {
  290.         switch ( cmdLineOptions[ index ] [ 0 ] ) {
  291.         case '-':
  292.             if ( cmdLineOptions[ index ] [ 1 ] == 'x' ) {
  293.                 pOptions->exFuncStrt = index + 1;
  294.             } /* endif */
  295.             break;
  296.         case '@':
  297.             pOptions->file = index;
  298.             pOptions->fromFile = 1;
  299.             strcpy( pOptions->listOfFilesFileNm
  300.                   , ( cmdLineOptions[ index ] ) + 1 );
  301.             break;
  302.         default: 
  303.             if ( !pOptions->fromFile ) {
  304.                 pOptions->nbFiles++;
  305.             } /* endif */
  306.             break;
  307.         } /* endswitch */
  308.         if ( pOptions->exFuncStrt ) {
  309.             break;
  310.         } /* endif */
  311.     } /* endfor */
  312.  
  313.     if ( pOptions->exFuncStrt ) {
  314.         index = pOptions->exFuncStrt;
  315.         if ( index < nbParms ) {
  316.             if ( cmdLineOptions[ index ] [ 0 ] == '@' ) {
  317.                 rc = setExFuncListFromFile( pOptions
  318.                                           , cmdLineOptions[ index ] + 1 );
  319.             } else {
  320.                 for ( ; index < nbParms; index++ ) {
  321.                     rc = addToExFuncList( pOptions
  322.                                         , cmdLineOptions[ index ] );
  323.                     if ( rc != 0 ) {
  324.                         break;
  325.                     } /* endif */
  326.                 } /* endfor */
  327.             } /* endif */
  328.         } /* endif */
  329.     } /* endif */
  330.  
  331.     return( rc );
  332. }
  333.  
  334. int setExFuncListFromFile( struct flowerOptions *pOptions
  335.                          , char *aFileNm )
  336. {
  337.     FILE *input = NULL;
  338.     char funcNm[ MAXFUNCNAMESIZE ];
  339.     int  rc = 0;
  340.  
  341.     input = fopen( aFileNm, "r" );
  342.     if ( input == NULL ) {
  343.         fprintf( stderr
  344.                , "\n***** error on fopen() for %s *****\n"
  345.                , aFileNm );
  346.         return( 1 );
  347.     } /* endif */
  348.  
  349.     while ( !feof( input ) ) {
  350.         fgets( funcNm, MAXFUNCNAMESIZE, input );
  351.         if ( feof( input ) ) {
  352.             break;
  353.         } /* endif */
  354.         strtok( funcNm, "\n\0" );
  355.         rc = addToExFuncList( pOptions, funcNm );
  356.         if ( rc != 0 ) {
  357.             break;
  358.         } /* endif */
  359.     } /* endwhile */
  360.  
  361.     fclose( input );
  362.     return( rc );
  363. }
  364.  
  365. int addToExFuncList( struct flowerOptions *pOptions
  366.                    , char *exFuncNm )
  367. {
  368.     #ifdef MY_DEBUG
  369.     char                      *thisFuncNm = "addToExFuncList\0";
  370.     char                      debug_msg[ MY_DEBUG_MSG_SZ ];
  371.     #endif
  372.     struct exFunc *pExFunc = NULL;
  373.     struct exFunc *pList = NULL;
  374.     struct exFunc *pHold = NULL;
  375.  
  376.     #ifdef MY_DEBUG
  377.     TRACE_ENTRY( thisFuncNm );
  378.     sprintf( debug_msg, " exFuncNm = %s", exFuncNm );
  379.     TRACE_MSG( thisFuncNm, exFuncNm );
  380.     #endif
  381.  
  382.     pExFunc = (struct exFunc *) malloc( sizeof( struct exFunc ) );
  383.     if ( pExFunc == NULL ) {
  384.         return( 3 );
  385.     } else {
  386.         memset( pExFunc, '\0', sizeof( struct exFunc ) );
  387.         pExFunc->next = NULL;
  388.         pExFunc->prev = NULL;
  389.         strcpy( pExFunc->funcNm, exFuncNm );
  390.     } /* endif */
  391.  
  392.     if ( pOptions->excludedFuncs == NULL ) {
  393.         pOptions->excludedFuncs = pExFunc;
  394.         return( 0 );
  395.     } /* endif */
  396.  
  397.     pList = pOptions->excludedFuncs;
  398.  
  399.     while ( pList != NULL ) {
  400.         pHold = pList;
  401.         pList = pList->next;
  402.     } /* endwhile */
  403.  
  404.     pHold->next = pExFunc;
  405.     pExFunc->prev = pHold;
  406.  
  407.     #ifdef MY_DEBUG
  408.     TRACE_EXIT( thisFuncNm );
  409.     #endif
  410.  
  411.     return( 0 );
  412. }
  413.  
  414. void freeExFuncList( struct flowerOptions *pOptions )
  415. {
  416.     struct exFunc *nextFunc = NULL;
  417.     struct exFunc *thisFunc = NULL;
  418.  
  419.     thisFunc = pOptions->excludedFuncs;
  420.  
  421.     while ( thisFunc != NULL ) {
  422.         nextFunc = thisFunc->next;
  423.         free( thisFunc );
  424.         thisFunc = nextFunc;
  425.     } /* endwhile */
  426.  
  427.     return;
  428. }
  429.  
  430. void cleanUpFileName( char *fileName )
  431. {
  432.     char tempFileName[ MAXFILENAMESIZE ];
  433.     int  i = 0;
  434.     int  j = 0;
  435.  
  436.     memset( tempFileName, '\0', MAXFILENAMESIZE );
  437.  
  438.     while ( fileName[ i ] ) {
  439.         if ( !isspace( fileName[ i ] ) ) {
  440.             tempFileName[ j ] = fileName[ i ];
  441.             j++;
  442.         } /* endif */
  443.         i++;
  444.     } /* endwhile */
  445.  
  446.     strncpy( fileName, tempFileName, MAXFILENAMESIZE );
  447.  
  448.     return;
  449. }
  450.  
  451. int processFiles( FILE *input
  452.                 , struct fileInfo *currentFile 
  453.                 , struct flowerOptions *pOptions )
  454. {
  455.     char          *inputContents;
  456.     char          *currentPosition = NULL;
  457.     int           inFunction = 0;
  458.     long          filePosition;
  459.     unsigned long fileSize;
  460.     char          *endOfContents;
  461.  
  462.     if ( fseek( input, 0, SEEK_END ) ) {
  463.         fprintf( stderr
  464.                , "%s error attempting fseek( input, 0, SEEK_END )\n"
  465.                , MYNAME );
  466.         return( 2 );
  467.     }
  468.  
  469.     filePosition = ftell( input );
  470.  
  471.     if ( fseek( input, 0, SEEK_SET ) ) {
  472.         fprintf( stderr
  473.                , "%s error attempting fseek( input, 0, SEEK_SET )\n"
  474.                , MYNAME );
  475.         return( 2 );
  476.     }
  477.  
  478.     if ( filePosition > 0 ) {
  479.         fileSize = filePosition;
  480.         inputContents = ( char * ) malloc( fileSize + 1 );
  481.         if ( inputContents == NULL ) {
  482.             fprintf( stderr
  483.                    , "%s error attempting ( char * ) malloc( %ld )\n"
  484.                    , MYNAME
  485.                    , fileSize );
  486.             return( 3 );
  487.         } /* endif */
  488.     } else {
  489.         fprintf( stderr
  490.                , "%s error EOF position ( %ld ) < 0\n"
  491.                , MYNAME
  492.                , filePosition );
  493.         return( 4 );
  494.     } /* endif */
  495.  
  496.     memset( inputContents, '\0', fileSize + 1 );
  497.     fread( inputContents, sizeof( char ), fileSize, input );
  498.     endOfContents = inputContents + fileSize;
  499.     currentPosition = inputContents;
  500.  
  501.     while ( currentPosition != NULL && currentPosition < endOfContents ) {
  502.         processTheText( inputContents
  503.                       , ¤tPosition
  504.                       , endOfContents
  505.                       , &inFunction
  506.                       , currentFile
  507.                       , pOptions );
  508.     };
  509.  
  510.     free( inputContents );
  511.  
  512.     return( 0 );
  513. }
  514.  
  515. void processTheText( char *inputContents
  516.                    , char **pCurrentPosition
  517.                    , char *endOfContents
  518.                    , int  *pInFunction
  519.                    , struct fileInfo *currentFile
  520.                    , struct flowerOptions *pOptions )
  521. {
  522.     char          *next = NULL;
  523.     char          currentFuncName [ MAXFUNCNAMESIZE ];
  524.     char          calledFuncName [ MAXFUNCNAMESIZE ];
  525.     int           rc = 0;
  526.  
  527.     next = getNextToken( *pCurrentPosition
  528.                        , inputContents
  529.                        , endOfContents );
  530.  
  531.     if ( next == NULL ) {
  532.         *pCurrentPosition = next;
  533.         return;
  534.     } /* endif */
  535.  
  536.     switch ( *next ) {
  537.     case '(':
  538.         if ( *pInFunction == 0 ) {
  539.             break;
  540.         } /* endif */
  541.         if ( getCalledFunction( inputContents
  542.                               , next
  543.                               , calledFuncName
  544.                               , pOptions ) ) {
  545.             if ( strlen( calledFuncName ) > 0 ) {
  546.                 addToCalledFuncList( currentFile->funcListEnd
  547.                                    , calledFuncName );
  548.             } /* endif */
  549.         } /* endif */
  550.         break;
  551.     case ')':
  552.         break;
  553.     case '{':
  554.         (*pInFunction)++;
  555.         if ( *pInFunction == 1 ) {
  556.             rc = getCurrentFunction( inputContents
  557.                                    , next
  558.                                    , currentFuncName
  559.                                    , pOptions );
  560.             if ( rc == 0 ) {
  561.                 /* we didn't really find a function */
  562.                 *pInFunction = 0;
  563.             } else {
  564.                 addToFuncList( currentFile, currentFuncName );
  565.             } /* endif */
  566.         } /* endif */
  567.         break;
  568.     case '}':
  569.         if ( *pInFunction > 0 ) {
  570.             (*pInFunction)--;
  571.         } /* endif */
  572.         break;
  573.     default :
  574.         break;
  575.     } /* endswitch */
  576.  
  577.     *pCurrentPosition = next;
  578.  
  579.     return;
  580. }
  581.  
  582. char *getNextToken( char *currentPosition
  583.                   , char *inputContents
  584.                   , char *endOfContents )
  585. {
  586.     /*
  587.     This function returns a pointer to the next
  588.     valid token of interest within inputContents.
  589.     It looks a little strange because we have to
  590.     account for such tokens being inside comments,
  591.     double quotes and single quotes.
  592.     Keep in mind that in this function we're moving
  593.     forward through inputContents.
  594.     */
  595.  
  596.     char *next;
  597.     int  done = 0;
  598.     int  insideSingleQuotes = 0;
  599.     int  insideDoubleQuotes = 0;
  600.     int  insideComment = 0;
  601.  
  602.     next = currentPosition + 1;
  603.  
  604.     while ( !done && next < endOfContents ) {
  605.         switch ( *next ) {
  606.         case '{':
  607.         case '}':
  608.         case '(':
  609.         case ')':
  610.         case '[':
  611.         case ']':
  612.         case ' ':
  613.         case CARRIAGE_RETURN:
  614.         case LINE_FEED:
  615.             if ( insideSingleQuotes || 
  616.                  insideDoubleQuotes || 
  617.                  insideComment ) {
  618.                 next++;
  619.             } else {
  620.                 done++;
  621.             } /* endif */
  622.             break;
  623.         case '\'':
  624.             if ( !insideComment && !insideDoubleQuotes ) {
  625.                 if ( *( next - 1 ) != '\\' ) {
  626.                     insideSingleQuotes = !insideSingleQuotes;
  627.                 } /* endif */
  628.             } /* endif */
  629.             next++;
  630.             break;
  631.         case '\"':
  632.             if ( !insideComment && !insideSingleQuotes ) {
  633.                 if ( *( next - 1 ) != '\\' ) {
  634.                     insideDoubleQuotes = !insideDoubleQuotes;
  635.                 } /* endif */
  636.             } /* endif */
  637.             next++;
  638.             break;
  639.         case '/':
  640.             if ( !insideSingleQuotes && !insideDoubleQuotes ) {
  641.                 if ( next + 1 <= endOfContents ) {
  642.                     if ( *( next + 1 ) == '*') {
  643.                         insideComment = 1;
  644.                     } /* endif */
  645.                 } /* endif */
  646.             } /* endif */
  647.             next++;
  648.             break;
  649.         case '*':
  650.             if ( !insideSingleQuotes && !insideDoubleQuotes ) {
  651.                 if ( next + 1 < endOfContents ) {
  652.                     if ( *( next + 1 ) == '/') {
  653.                         insideComment = 0;
  654.                     } /* endif */
  655.                 } /* endif */
  656.                 /*
  657.                 Added this 'if' to account for source
  658.                 code that starts with a comment in position
  659.                 one of the first line.  Also gets rid of
  660.                 an apparent bug with comments starting
  661.                 out (K&R only know why) with the sequence
  662.                 slash-splat-slash.
  663.                 */
  664.                 if ( next - 1 >= inputContents ) {
  665.                     if ( *( next - 1 ) == '/' ) {
  666.                         insideComment = 1;
  667.                     } /* endif */
  668.                 } /* endif */
  669.             } /* endif */
  670.             next++;
  671.             break;
  672.         default:
  673.             next++;
  674.             break;
  675.         } /* endswitch */
  676.     } /* endwhile */
  677.  
  678.     if ( next >= endOfContents ) {
  679.         next = NULL;
  680.     } /* endif */
  681.  
  682.     return( next );
  683. }
  684.  
  685. char *getPrevToken( char *inputContents
  686.                   , char *currentPosition )
  687. {
  688.     /*
  689.     This function returns a pointer to the previous
  690.     valid token of interest within inputContents.
  691.     It looks a little strange because we have to
  692.     account for such tokens being inside comments,
  693.     double quotes and single quotes.
  694.     Keep in mind that in this function we're moving
  695.     backward through inputContents.
  696.     */
  697.  
  698.     char *prev;
  699.     int  done = 0;
  700.     int  insideSingleQuotes = 0;
  701.     int  insideDoubleQuotes = 0;
  702.     int  insideComment = 0;
  703.  
  704.     prev = currentPosition - 1;
  705.  
  706.     while ( !done && prev >= inputContents ) {
  707.         switch ( *prev ) {
  708.         case '(':
  709.         case ')':
  710.         case '{':
  711.         case '}':
  712.         case '[':
  713.         case ']':
  714.         case ' ':
  715.         case ',':
  716.         case ';':
  717.         case '|':
  718.         case '&':
  719.         case '=':
  720.         case CARRIAGE_RETURN:
  721.         case LINE_FEED:
  722.             if ( insideSingleQuotes || 
  723.                  insideDoubleQuotes || 
  724.                  insideComment ) {
  725.                 prev--;
  726.             } else {
  727.                 done++;
  728.             } /* endif */
  729.             break;
  730.         case '\'':
  731.             if ( !insideComment && !insideDoubleQuotes ) {
  732.                 if ( prev != currentPosition ) {
  733.                     if ( *( prev + 1 ) != '\\' ) {
  734.                         insideSingleQuotes = !insideSingleQuotes;
  735.                     } /* endif */
  736.                 } else {
  737.                     insideSingleQuotes = !insideSingleQuotes;
  738.                 } /* endif */
  739.             } /* endif */
  740.             prev--;
  741.             break;
  742.         case '\"':
  743.             if ( !insideComment && !insideSingleQuotes ) {
  744.                 if ( prev != currentPosition ) {
  745.                     if ( *( prev + 1 ) != '\\' ) {
  746.                         insideDoubleQuotes = !insideDoubleQuotes;
  747.                     } /* endif */
  748.                 } else {
  749.                     insideDoubleQuotes = !insideDoubleQuotes;
  750.                 } /* endif */
  751.             } /* endif */
  752.             prev--;
  753.             break;
  754.         case '/':
  755.             if ( !insideSingleQuotes && !insideDoubleQuotes ) {
  756.                 if ( prev != currentPosition ) {
  757.                     if ( *( prev - 1 ) == '*') {
  758.                         insideComment = 1;
  759.                     } /* endif */
  760.                 } /* endif */
  761.             } /* endif */
  762.             prev--;
  763.             break;
  764.         case '*':
  765.             if ( !insideSingleQuotes && !insideDoubleQuotes ) {
  766.                 if ( prev != currentPosition ) {
  767.                     if ( *( prev - 1 ) == '/') {
  768.                         insideComment = 0;
  769.                     } /* endif */
  770.                 } /* endif */
  771.             } /* endif */
  772.             prev--;
  773.             break;
  774.         default:
  775.             prev--;
  776.             break;
  777.         } /* endswitch */
  778.     } /* endfor */
  779.  
  780.     if ( prev < inputContents ) {
  781.         prev = NULL;
  782.     } /* endif */
  783.  
  784.     return( prev );
  785. }
  786.  
  787. int getCalledFunction( char *inputContents
  788.                      , char *next
  789.                      , char *calledFuncName
  790.                      , struct flowerOptions *pOptions )
  791. {
  792.     /*
  793.     This function gets a string which may be
  794.     a called function name.  It then matches the
  795.     string against a list of reserved words which
  796.     look like functions to the basic algorithm.  If
  797.     the string is not found or is a reserved word 
  798.     0 is returned, otherwise 1 is returned.
  799.     */
  800.  
  801.     #ifdef MY_DEBUG
  802.     char            *thisFuncNm = "getCalledFunction\0";
  803.     #endif
  804.     char *prev = NULL;
  805.     char *funcStart = NULL;
  806.     int  rc = 0;
  807.  
  808.     #ifdef MY_DEBUG
  809.     TRACE_ENTRY( thisFuncNm );
  810.     #endif
  811.  
  812.     memset( calledFuncName, '\0', MAXFUNCNAMESIZE );
  813.     prev = getPrevToken( inputContents
  814.                        , next );
  815.     if ( prev == NULL ) {
  816.         return( 0 );
  817.     } /* endif */
  818.  
  819.     funcStart = prev;
  820.  
  821.     if ( (next - prev) < 2 ) {
  822.         while ( funcStart != NULL && *funcStart == ' ' ) {
  823.             prev = funcStart;
  824.             if ( *prev == ',' ||
  825.                  *prev == '|' ||
  826.                  *prev == '=' ||
  827.                  *prev == '&' ) {
  828.                 break;
  829.             } /* endif */
  830.             funcStart = getPrevToken( inputContents
  831.                                     , funcStart );
  832.         } /* endwhile */
  833.     } /* endif */
  834.  
  835.     if ( prev == NULL ) {
  836.         return( 0 );
  837.     } /* endif */
  838.  
  839.     if ( *prev == ',' ||
  840.          *prev == '|' ||
  841.          *prev == '=' ||
  842.          *prev == '&' ) {
  843.         /* inside if, function args, cast, for or while */
  844.         prev++;
  845.     } /* endif */
  846.  
  847.     if ( (next - prev) > 1 && (next - prev) < MAXFUNCNAMESIZE ) {
  848.         memcpy( calledFuncName, prev + 1, (next - prev) - 1 );
  849.         cleanUpFuncName( calledFuncName );
  850.         if ( !isReservedWord( calledFuncName ) &&
  851.              !isReservedSymbol( calledFuncName ) &&
  852.              !isExcludedFunc( calledFuncName, pOptions ) ) {
  853.             rc = 1;
  854.         } /* endif */
  855.     } /* endif */
  856.  
  857.     #ifdef MY_DEBUG
  858.     TRACE_EXIT( thisFuncNm );
  859.     #endif
  860.  
  861.     return( rc );
  862. }
  863.  
  864. int getCurrentFunction( char *inputContents
  865.                       , char *next
  866.                       , char *currentFuncName
  867.                       , struct flowerOptions *pOptions )
  868. {
  869.     /*
  870.     This function gets a string which is the
  871.     current function name.  If the string is
  872.     longer than 1 byte and shorter than the
  873.     maximum allowable length 1 is returned,
  874.     otherwise 0 is returned.  0 is also returned if
  875.     we've been fooled by a struct or union
  876.     declaration.
  877.     */
  878.  
  879.     #ifdef MY_DEBUG
  880.     char            *thisFuncNm = "getCurrentFunction\0";
  881.     char            debug_msg[ MY_DEBUG_MSG_SZ ];
  882.     #endif
  883.     char *prev = NULL;
  884.     char *funcStart = NULL;
  885.     int  rc = 0;
  886.     int  inParens = 0;
  887.  
  888.     #ifdef MY_DEBUG
  889.     TRACE_ENTRY( thisFuncNm );
  890.     sprintf( debug_msg, " next = %p", next );
  891.     TRACE_MSG( thisFuncNm, debug_msg );
  892.     #endif
  893.  
  894.     memset( currentFuncName
  895.           , '\0'
  896.           , MAXFUNCNAMESIZE );
  897.  
  898.     prev = getPrevToken( inputContents
  899.                        , next );
  900.  
  901.     do {
  902.         /* get to the outermost parentheses */
  903.         if ( *prev == ')' ) {
  904.             if ( inParens == 0 ) {
  905.                 /* outermost closing paren */
  906.                 if ( fooledByStructOrUnion( next, prev ) ) {
  907.                     #ifdef MY_DEBUG
  908.                     TRACE_MSG( thisFuncNm, "fooled by struct or union\0" );
  909.                     TRACE_EXIT( thisFuncNm );
  910.                     #endif
  911.                     return( 0 );
  912.                 } /* endif */
  913.             } /* endif */
  914.             inParens++;
  915.         } /* endif */
  916.         if ( *prev == '(' ) {
  917.             if ( inParens ) {
  918.                 inParens--;
  919.                 if ( inParens == 0 ) {
  920.                     break;
  921.                 } /* endif */
  922.             } /* endif */
  923.         } /* endif */
  924.         prev = getPrevToken( inputContents, prev );
  925.     } while ( prev != NULL ) ;
  926.  
  927.     if ( prev >= inputContents ) {
  928.         funcStart = getPrevToken( inputContents, prev );
  929.         if ( *funcStart == ',' ) {
  930.             /*
  931.             fooled by a structure initialization,
  932.             probably some evil global variable
  933.             */
  934.             #ifdef MY_DEBUG
  935.             TRACE_MSG( thisFuncNm, "fooled by structure initialization\0" );
  936.             TRACE_EXIT( thisFuncNm );
  937.             #endif
  938.             return( 0 );
  939.         } /* endif */
  940.         while ( funcStart != NULL && (prev - funcStart == 1) ) {
  941.             /* 
  942.             This "while" is here because apparently
  943.             SOME people think it's a good idea to put
  944.             white space between the name of a function
  945.             and the opening parenthesis denoting the
  946.             beginning of the argument list.  You know
  947.             who you are... and so do we.
  948.             */
  949.             if ( *funcStart == ',' ) {
  950.                 /* fooled by a structure initialization */
  951.                 #ifdef MY_DEBUG
  952.                 TRACE_MSG( thisFuncNm, "fooled by structure initialization\0" );
  953.                 TRACE_EXIT( thisFuncNm );
  954.                 #endif
  955.                 return( 0 );
  956.             } /* endif */
  957.             prev = funcStart;
  958.             funcStart = getPrevToken( inputContents
  959.                                     , funcStart );
  960.         } /* endwhile */
  961.         if ( funcStart != NULL && 
  962.              (prev - funcStart) < MAXFUNCNAMESIZE ) {
  963.             memcpy( currentFuncName
  964.                   , funcStart + 1
  965.                   , (prev - funcStart) - 1 );
  966.             cleanUpFuncName( currentFuncName );
  967.             if ( !isReservedWord( currentFuncName )  &&
  968.                  !isReservedSymbol( currentFuncName ) &&
  969.                  !isExcludedFunc( currentFuncName, pOptions ) ) {
  970.                 rc = 1;
  971.             } /* endif */
  972.             if ( strlen( currentFuncName ) == 0 ) {
  973.                 rc = 0;
  974.             } /* endif */
  975.         } /* endif */
  976.     } /* endif */
  977.  
  978.     #ifdef MY_DEBUG
  979.     TRACE_EXIT( thisFuncNm );
  980.     #endif
  981.  
  982.     return( rc );
  983. }
  984.  
  985. int fooledByStructOrUnion( char *curlyBrace, char *paren )
  986. {
  987.     /*
  988.     This function indicates whether or not
  989.     the algorithm has been fooled by a struct
  990.     or union definition, indicated by there
  991.     being something besides whitespace between
  992.     the closing paren of the function declaration
  993.     and the next semicolon.
  994.     */
  995.  
  996.     char   *someText = NULL;
  997.     char   *nextSemicolon = NULL;
  998.     size_t someTextLen = 0;
  999.     size_t i = 0;
  1000.     int    rc = 1;
  1001.  
  1002.     if ( paren == NULL ) {
  1003.         return( 0 );
  1004.     } /* endif */
  1005.  
  1006.     nextSemicolon = strstr( paren, ";\0" );
  1007.  
  1008.     if ( nextSemicolon == NULL ) {
  1009.         return( 0 );
  1010.     } /* endif */
  1011.  
  1012.     if ( curlyBrace < nextSemicolon ) {
  1013.         return( 0 );
  1014.     } /* endif */
  1015.  
  1016.     someTextLen = nextSemicolon - paren;
  1017.  
  1018.     if ( someTextLen < 2 ) {
  1019.         return( 1 );
  1020.     } /* endif */
  1021.  
  1022.     someText = ( char * ) malloc( someTextLen );
  1023.     if ( someText == NULL ) {
  1024.         return( 1 );
  1025.     } /* endif */
  1026.  
  1027.     memset( someText, '\0', someTextLen );
  1028.     memcpy( someText, paren + 1, someTextLen - 1 );
  1029.  
  1030.     while ( someText[ i ] ) {
  1031.         if ( !isspace( someText[ i ] ) ) {
  1032.             rc = 0;
  1033.             break;
  1034.         } /* endif */
  1035.         i++;
  1036.     } /* endwhile */
  1037.  
  1038.     free( someText );
  1039.     return( rc );
  1040. }
  1041.  
  1042. int isReservedWord( char *funcName )
  1043. {
  1044.     /*
  1045.     This function returns 1 if the passed
  1046.     funcName equals any of the reserved
  1047.     words listed.  Feel free to add your
  1048.     own or trade them with friends.
  1049.     */
  1050.  
  1051.     if ( !strcmp( "if\0", funcName ) ) {
  1052.         return( 1 );
  1053.     } /* endif */
  1054.  
  1055.     if ( !strcmp( "while\0", funcName ) ) {
  1056.         return( 1 );
  1057.     } /* endif */
  1058.  
  1059.     if ( !strcmp( "switch\0", funcName ) ) {
  1060.         return( 1 );
  1061.     } /* endif */
  1062.  
  1063.     if ( !strcmp( "return\0", funcName ) ) {
  1064.         return( 1 );
  1065.     } /* endif */
  1066.  
  1067.     if ( !strcmp( "for\0", funcName ) ) {
  1068.         return( 1 );
  1069.     } /* endif */
  1070.  
  1071.     if ( !strcmp( "exit\0", funcName ) ) {
  1072.         return( 1 );
  1073.     } /* endif */
  1074.  
  1075.     if ( !strcmp( "case\0", funcName ) ) {
  1076.         return( 1 );
  1077.     } /* endif */
  1078.  
  1079.     if ( !strcmp( "sizeof\0", funcName ) ) {
  1080.         return( 1 );
  1081.     } /* endif */
  1082.  
  1083.     if ( !strcmp( "offsetof\0", funcName ) ) {
  1084.         return( 1 );
  1085.     } /* endif */
  1086.  
  1087.     return( 0 );
  1088. }
  1089.  
  1090. int isReservedSymbol( char *funcName )
  1091. {
  1092.     if ( !strcmp( "*\0", funcName ) ) {
  1093.         return( 1 );
  1094.     } /* endif */
  1095.  
  1096.     if ( !strcmp( "!\0", funcName ) ) {
  1097.         return( 1 );
  1098.     } /* endif */
  1099.  
  1100.     if ( !strcmp( "&\0", funcName ) ) {
  1101.         return( 1 );
  1102.     } /* endif */
  1103.  
  1104.     if ( !strcmp( "&&\0", funcName ) ) {
  1105.         return( 1 );
  1106.     } /* endif */
  1107.  
  1108.     if ( !strcmp( "||\0", funcName ) ) {
  1109.         return( 1 );
  1110.     } /* endif */
  1111.  
  1112.     if ( !strcmp( "[\0", funcName ) ) {
  1113.         return( 1 );
  1114.     } /* endif */
  1115.  
  1116.     if ( !strcmp( "]\0", funcName ) ) {
  1117.         return( 1 );
  1118.     } /* endif */
  1119.  
  1120.     if ( !strcmp( "-\0", funcName ) ) {
  1121.         return( 1 );
  1122.     } /* endif */
  1123.  
  1124.     if ( !strcmp( "--\0", funcName ) ) {
  1125.         return( 1 );
  1126.     } /* endif */
  1127.  
  1128.     if ( !strcmp( "+\0", funcName ) ) {
  1129.         return( 1 );
  1130.     } /* endif */
  1131.  
  1132.     if ( !strcmp( "++\0", funcName ) ) {
  1133.         return( 1 );
  1134.     } /* endif */
  1135.  
  1136.     return( 0 );
  1137. }
  1138.  
  1139. int isExcludedFunc( char *funcName
  1140.                   , struct flowerOptions *pOptions )
  1141. {
  1142.     #ifdef MY_DEBUG
  1143.     char            *thisFuncNm = "isExcludedFunc\0";
  1144.     #endif
  1145.     struct exFunc *pList = NULL;
  1146.  
  1147.     #ifdef MY_DEBUG
  1148.     TRACE_ENTRY( thisFuncNm );
  1149.     TRACE_MSG( thisFuncNm, funcName );
  1150.     #endif
  1151.  
  1152.     pList = pOptions->excludedFuncs;
  1153.  
  1154.     while ( pList != NULL ) {
  1155.         if ( !strcmp( pList->funcNm, funcName ) ) {
  1156.             #ifdef MY_DEBUG
  1157.             TRACE_MSG( thisFuncNm, "rc = 1\0" );
  1158.             TRACE_EXIT( thisFuncNm );
  1159.             #endif
  1160.             return( 1 );
  1161.         } /* endif */
  1162.         pList = pList->next;
  1163.     } /* endwhile */
  1164.  
  1165.     #ifdef MY_DEBUG
  1166.     TRACE_MSG( thisFuncNm, "rc = 0\0" );
  1167.     TRACE_EXIT( thisFuncNm );
  1168.     #endif
  1169.  
  1170.     return( 0 );
  1171. }
  1172.  
  1173. void cleanUpFuncName( char *funcName )
  1174. {
  1175.     /*
  1176.     This function gets rid of characters
  1177.     that may be "stuck to" the function
  1178.     name.  For instance, a developer may
  1179.     write "if ( !strncmp..." and we don't
  1180.     want to include the ! character when
  1181.     outputting the function names.
  1182.     */
  1183.  
  1184.     #ifdef MY_DEBUG
  1185.     char            *thisFuncNm = "cleanUpFuncName\0";
  1186.     #endif
  1187.     char cleanedFuncName[ MAXFUNCNAMESIZE ];
  1188.     int  i = 0;
  1189.     int  j = 0;
  1190.  
  1191.     #ifdef MY_DEBUG
  1192.     TRACE_ENTRY( thisFuncNm );
  1193.     TRACE_MSG( thisFuncNm, funcName );
  1194.     #endif
  1195.  
  1196.     memset( cleanedFuncName
  1197.           , '\0'
  1198.           , MAXFUNCNAMESIZE );
  1199.  
  1200.     while ( funcName[ i ] != 0 ) {
  1201.         if ( !isspace( funcName[ i ] ) && 
  1202.              !isEmbeddedSymbol( funcName[ i ] ) ) {
  1203.             cleanedFuncName[ j ] = funcName[ i ];
  1204.             j++;
  1205.         } /* endif */
  1206.         i++;
  1207.     } /* endwhile */
  1208.  
  1209.     strncpy( funcName, cleanedFuncName, MAXFUNCNAMESIZE );
  1210.  
  1211.     #ifdef MY_DEBUG
  1212.     TRACE_MSG( thisFuncNm, cleanedFuncName );
  1213.     TRACE_EXIT( thisFuncNm );
  1214.     #endif
  1215.  
  1216.     return;
  1217. }
  1218.  
  1219. int isEmbeddedSymbol( char aChar )
  1220. {
  1221.     /*
  1222.     This function returns a true if aChar is a
  1223.     character that may be "stuck to" the function 
  1224.     name, but aren't actually part of the 
  1225.     function name.
  1226.     */
  1227.  
  1228.     char *symbolList = ".!%^&*=+|/? \'\"\0";
  1229.  
  1230.     if ( strchr( symbolList, aChar ) != NULL ) {
  1231.         return( 1 );
  1232.     } /* endif */
  1233.  
  1234.     return( 0 );
  1235. }
  1236.  
  1237.